﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Algobox.JuicyLib.Apps.Sterling
{
    public class SterlingDailyOptionsFile
    {
        public SterlingDailyOptionsFile(SterlingTradeImporter2 importer)
        {
            Importer = importer;
        }

        SterlingTradeImporter2 Importer { get; set; }

        const char SEPERATOR_COL = ',';
        const int COLUMNS = 36;
        const int IX_USER = 0;
        const int IX_ACCOUNT = 2;
        const int IX_SIDE = 3;
        const int IX_STERLINGSYMBOL = 5;
        const int IX_SYMBOL = 5;
        const int IX_EXPIRY = 6;
        const int IX_STRIKE = 7;
        const int IX_PUTCALL = 8;
        const int IX_QUANTITY = 11;
        const int IX_PRICE = 12;
        const int IX_DEST = 13;
        const int IX_TIME = 15;
        const int IX_ORDERID = 18;
        const int IX_RECORDID = 35;
        const int IX_CPTY = 13;
        const int IX_FLAG = 33;
        //const int IX_CCY = 99999;
        const int IX_ORDERTIME = 20;
        const int IX_SETTLEMENTDATE = 27;

        public bool ImportOptionsFile(string filename, string data, List<string> ignoredAccounts)
        {
            int countMissing = 0;
            int countSuccess = 0;

            string archiveDir = String.Empty;
            DateTime fileDate = DateTime.Now.Date;

            try
            {
                // get file date
                archiveDir = Path.GetFileNameWithoutExtension(filename);
                archiveDir = archiveDir.Substring(archiveDir.Length - 8);
                fileDate = DateTime.ParseExact(archiveDir, "yyyyMMdd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None);
            }
            catch
            {
                JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to parse date from '{0}' in filename '{1}' so using {2}", archiveDir, filename, fileDate);
                Console.WriteLine("Failed to parse date from '{0}' in filename '{1}' so using {2}", archiveDir, filename, fileDate);
            }

            // get the location to archive the file
            archiveDir = Importer.ArchiveDirectory + fileDate.ToString("yyyy/MM/dd") + "/";

            List<string> tradeKeys = null;
            try
            {
                // try and load all trade identifiers for this trade date to insure we don't import dupes
                tradeKeys = Importer.LiquidViewLinq.Trades.Where(x => x.Host == Importer.HostName && x.TradeTime > fileDate && x.TradeTime < fileDate.AddDays(1)).Select(t => t.ExchangeOrderId + t.ExchangeTradeId).ToList();
            }
            catch (Exception e)
            {
                JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to load trade identifiers for host {0}, cannot continue with this file. Exception({1})", Importer.HostName, e);
                Console.WriteLine("Failed to load trade identifiers for host {0}, cannot continue with this file. Exception({1})", Importer.HostName, e);
                return false;
            }

            try
            {
                var query = from csvline in data.Split('\n')
                            let csv = csvline.Split(SEPERATOR_COL)
                            where csv.Length >= COLUMNS
                            select new
                            {
                                User = csv[IX_USER],
                                Account = csv[IX_ACCOUNT],
                                Side = csv[IX_SIDE],
                                SterlingSymbol = csv[IX_STERLINGSYMBOL],
                                UnderlyingSymbol = csv[IX_SYMBOL],
                                Expiry = csv[IX_EXPIRY],
                                StrikePrice = csv[IX_STRIKE],
                                PutCall = csv[IX_PUTCALL],
                                Quantity = csv[IX_QUANTITY],
                                Price = csv[IX_PRICE],
                                Destination = csv[IX_DEST],
                                Time = csv[IX_TIME],
                                OrderId = csv[IX_ORDERID],
                                RecordId = csv[IX_RECORDID],
                                Counterparty = csv[IX_CPTY],
                                Flag = csv[IX_FLAG],
                                OrderTime = csv[IX_ORDERTIME],
                                SettlementDate = csv[IX_SETTLEMENTDATE]
                            };

                string exchange, orderId, tradeId, account;
                DateTime tradeTime, expiry;
                long quantity;
                decimal price, strike;

                var enumerableQuery = query.GetEnumerator();
                for (int i = 0; enumerableQuery.MoveNext(); i++)
                {
                    //if (i == 0)
                    //    continue;

                    var row = enumerableQuery.Current;

                    try
                    {
                        account = row.Account;
                        orderId = "O-" + account + "-" + row.OrderId;
                        tradeId = orderId + "-" + row.RecordId;

                        // if trade exists then continue
                        if (tradeKeys.Contains(orderId + tradeId))
                            continue;

                        if (ignoredAccounts.Contains(account))
                            continue;

                        ++countMissing;

                        // quantity
                        if (!Int64.TryParse(row.Quantity, out quantity))
                        {
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to parse quantity for record Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6})", account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId);
                            Console.WriteLine("Can't parse quantity:  " + row.Quantity);
                            continue;
                        }

                        // quantity side
                        if (row.Side != "B")
                            quantity = -quantity;

                        // price
                        if (!Decimal.TryParse(row.Price, out price))
                        {
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to parse price for record Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6})", account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId);
                            Console.WriteLine("Can't parse price:  " + row.Price);
                            continue;
                        }

                        // trade time
                        if (!DateTime.TryParseExact(row.Time,
                               "MM/dd/yy HH:mm:ss",
                               System.Globalization.CultureInfo.InvariantCulture,
                               System.Globalization.DateTimeStyles.None,
                               out tradeTime))
                        {
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to parse date for record Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6})", account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId);
                            Console.WriteLine("Can't parse date:  " + row.Time);
                            continue;
                        }
                        
                        // strike
                        if (!Decimal.TryParse(row.StrikePrice, out strike))
                        {
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to parse StrikePrice for record Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6}) Strike({7})", account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId, row.StrikePrice);
                            Console.WriteLine("Can't parse price:  " + row.Price);
                            continue;
                        }

                        // expiry date 
                        if (!DateTime.TryParseExact(row.Expiry,
                               "yyyyMMdd",
                               System.Globalization.CultureInfo.InvariantCulture,
                               System.Globalization.DateTimeStyles.None,
                               out expiry))
                        {
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to parse date for record Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6}) Expiry({7})", account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId, row.Expiry);
                            Console.WriteLine("Can't parse date:  " + row.Time);
                            continue;
                        }

                        // ExchangeMIC
                        exchange = Importer.GetExchangeMIC(row.Destination);

                        if (exchange == "XXXX")
                        {
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to find correct ExchangeMIC for {0} so defaulting to XXXX", row.Destination);
                        }

                        // insert trade into the database
                        int result = Importer.LiquidViewLinq.ImportTradeOption(
                            Importer.HostName,
                            orderId,
                            tradeId,
                            exchange,
                            orderId, tradeId, account, "USD", row.UnderlyingSymbol, expiry, 
                            row.PutCall[0], strike, quantity, price, tradeTime, row.Counterparty,
                            false, false, false, null, null, null, 
                            Importer.ProcessName + " imported from " + filename,
                            row.User);


                        if (result == 0)
                        {
                            ++countSuccess;
                        }
                        else
                        {
                            Console.WriteLine("Failed ImportTradeOption Returned({7}) Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6})", row.Account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId, result);
                            JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed ImportTradeOption Returned({7}) Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6})", row.Account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId, result);
                        }
                    }
                    catch (Exception e)
                    {
                        Console.WriteLine("Failed to import trade!\r\n" + e);
                        JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to import trade Account({0}) Symbol({1}) Quantity({2}) Price({3}) Date({4}) OrderId({5}) TradeId({6}) Exception({7})", row.Account, row.SterlingSymbol, row.Quantity, row.Price, row.Time, row.OrderId, row.RecordId, e.Message);
                        continue;
                    }
                }

            }
            catch (Exception e)
            {
                JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Failed to extract data from csv format. Exception({0})", e);
                Console.WriteLine("Failed to extract data from csv format. Exception({0})", e);

                return false;
            }
            
            // archive the file
            try
            {
                if (!Importer.CheckDirectory(archiveDir))
                {
                    Console.WriteLine("Could not create directory " + archiveDir + ", " + filename + " not archived");
                    JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Could not create directory " + archiveDir + ", " + filename + " not archived");
                }
                else
                {
                    File.WriteAllText(archiveDir + filename, data, Encoding.ASCII);
                    Console.WriteLine("Successfully archived " + filename);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("Unknow error when trying to archive '" + filename + "' to " + archiveDir + " Exception({0})", e.Message);
                JuicyLib.SQL.LiquidView.LiquidViewHelper.LogException(Importer.ProcessName, "Unknow error when trying to archive '" + filename + "' to " + archiveDir + " Exception({0})", e.Message);
            }

            return true;
        }

    }
}
